import sys
from dnscope.registry import TEST_REGISTRY, call_hook, HOOK_REGISTRY

class Test(object):
     
    def __init__(self, testinfo, suitname):
        self.info = testinfo
        self.suit = suitname
        self.defined = True
        self.passed = None
        self.failed = None
   
    @property
    def name(self):
        return self.info.partition(':')[0]
        
    def run(self):
        call_hook('before_each', 'test', self)
        try:
            run_test = TEST_REGISTRY[self.suit][self.info]
            run_test()
        except KeyError, e:
            self.defined = False
        except AssertionError, e:
            self.failed = True
	    raise AssertionError(e)
        else:
            self.passed = True

        finally:
            call_hook('after_each', 'test', self)


class TestSuit(object):
   
    def __init__(self, suit_name):
      
        self.name = suit_name
        self.tests = None

    def get_tests(self, tests_to_run=None):
        #print "self:",self.name
        #print TEST_REGISTRY
        #print HOOK_REGISTRY
        
        tests = {}
        try:
          if not tests_to_run:
            for test_info in TEST_REGISTRY[self.name].keys():
                testname = test_info.partition(':')[0]
                tests[testname] = Test(test_info,self.name)
          else:
            for t in tests_to_run:
                for test_info in TEST_REGISTRY[self.name].keys():
                    testname = test_info.partition(':')[0]
                    if t == testname:
                        tests[testname] = Test(test_info,self.name)
                        break
        except KeyError, e:
          sys.stderr.write("\n\nTestsuit %s not exist!\n\n" % self.name)
          raise SystemExit(1)

        return tests

    @property
    def testnames(self):
        return [testname for testname in self.tests.keys()]


    def run(self, tests_to_run=None):

        self.tests = self.get_tests(tests_to_run)
        if not tests_to_run:
            tests_to_run = self.testnames

        try:
           call_hook('before_each','suit', self)
        
           all_tests = []
           tests_passed = []
           tests_failed = []
           tests_undefined = []

           for t in tests_to_run:
	     	try:
               		if t not in self.testnames:
                 		sys.stderr.write("Case: %s not exist!\n" % t)
                 		continue

               		test = self.tests[t]
               		test.run()
                except AssertionError, e:
                        print e
                finally:
               		if not test.defined:
                		tests_undefined.append(t)
               		elif test.passed:
                		tests_passed.append(t)
               		elif test.failed: 
                		tests_failed.append(t)

               		all_tests.append(t)

        finally:
           call_hook('after_each','suit', self)
       
        return TestSuitResult(self, all_tests, tests_passed, tests_failed, tests_undefined)

class TestSuitResult(object):

    def __init__(self, testsuit, all_tests, tests_passed, tests_failed, tests_undefined):
        self.testsuit = testsuit
        self.tests_passed = tests_passed
        self.tests_failed = tests_failed
        self.tests_undefined = tests_undefined
        self.all_tests = all_tests

    @property
    def passed(self):
        return len(self.all_tests) == len(self.tests_passed)
        

class TotalResult(object):

    def __init__(self, testsuit_results):
        self.testsuit_results = testsuit_results
        self.passed_num = 0
        self.failed_num = 0
        self.undefined_num = 0
        self.tests_total = 0

        for suit_result in self.testsuit_results:
            self.passed_num += len(suit_result.tests_passed)
            self.failed_num += len(suit_result.tests_failed)
            self.undefined_num += len(suit_result.tests_undefined)
            self.tests_total += len(suit_result.all_tests)

    @property
    def testsuits_ran(self):
        return len(self.testsuit_results)
        
    @property
    def testsuits_passed(self):
        return len([result for result in self.testsuit_results if result.passed])

if __name__ == '__main__':
    
    def qtype_test():
        print "qtype teeeeeeeeeeeeest"

    def dnssec_test():
        print "dnssec teeeeeeeeeeeest"

    TEST_REGISTRY = {
                      'query': {
                                  'qtype': qtype_test,
                                  'dnssec': dnssec_test
                               }
                    }

    print "****Check TestSuit.run()"
    testsuit = TestSuit('query')
    print testsuit.tests
    testsuit.run()
    
    print "****Check TestSuit.run(['dnssec'])"
    testsuit.run(['dnssec'])
    
    print "****Check class Test"
    test = Test('dnssec', 'query')
    test.run()
